#include"Header.h"
#include<iostream>
#include<sstream>
#include<sys/stat.h>
#include<regex>
#include<ctype.h>
#include"HardData.h"
#include"SoftData.h"
#include<algorithm>

const std::string Header::k[] = {"Server:", "Connection:", "Content-Type:", "Content-Length:", "Last-Modified:"};
const std::map<std::string, std::string> Header::retType = {{"\\S*.js", "application/javascript"}, {"\\S*.png", "image/png"}, {"\\S*.ico", "image/ico"}};

Header::Header(){
  h[k[0]] = "my-web";
  h[k[1]] = "keep-alive";
}

Header::Header(const std::string &s){
  std::istringstream iss(s);
  std::string k, v;
  iss >> sf;
  iss >> ss;
  iss >> st;
  while(iss >> k){
    iss.get();
    getline(iss, v, '\r');
    transform(k.begin(), k.end(), k.begin(), tolower);
    h[k] = v;
  }
  if(ss == "/favicon.ico"){
  }else if(h.find("referer:") != h.end()){
    adjustUrl();
  }
}

void Header::setsct(const std::string &msg, std::shared_ptr<RetData> &body, std::string &s){
  std::string path = "resources/static/" + msg;
  for(auto &[r, t]: retType)
    if(std::regex_match(msg, std::regex(r))){
      h[k[2]] = t;
      setLM(path);
      setscl(path, body);
      get(s);
      break;
    }  
}

void Header::seterror(std::shared_ptr<RetData> &body, std::string &s){
  ss = "404";
  st = "Not Found";
  h[k[2]] = "text/html";
  setscl("error", body);
  get(s);
}

void Header::setdct(const std::string &msg, std::shared_ptr<RetData> &body, std::string &s){
  if(std::regex_match(msg, std::regex("\\S*.html"))){
    std::string path;
    h[k[2]] = "text/html";
    path = "resources/html/" + msg;
    setscl(path, body);
    get(s);
  }else if(std::regex_match(msg, std::regex("\\{[\\S\\s]*\\}"))){
    h[k[2]] = "application/json";
    setdcl(msg, body);
    get(s);
  }
}

void Header::setdcl(const std::string &data, std::shared_ptr<RetData> &body){
  std::ostringstream oss;
  oss << data.length();
  h[k[3]] = oss.str();
  auto &&sd = std::make_shared<SoftData>();
  body = sd;
  sd->data << data;
  sd->type = "soft";
}

void Header::setscl(const std::string &path, std::shared_ptr<RetData> &body){
  auto &&f = std::make_shared<HardData>(path);
  body = f;
  f->type = "hard";
  std::ostringstream oss;
  oss << f->size;
  h[k[3]] = oss.str();
}

void Header::adjustUrl(){
  std::string &r = h["referer:"];
  std::smatch m;
  std::regex_search(r, m, std::regex("//\\S*?(?=/)"));
  std::string &&pre = m.suffix();
  std::regex_search(pre, m, std::regex("\\S*(?=/)"));
  ss = std::regex_replace(ss, std::regex(std::string(m[0])), "");
}

std::string Header::getl(){
  return sf + " " + ss + " " + st;
}

void Header::setLM(const std::string &path){
  if(h.find(k[4]) == h.end()){
    struct stat st;
    if(stat(path.c_str(), &st) != -1){
      std::ostringstream oss;
      oss << st.st_mtime;
      h[k[4]] = oss.str();
    }
  }
}

void Header::get(std::string &s){
  s += sf;
  s += " ";
  s += ss;
  s += " ";
  s += st;
  s += "\r\n";
  for(auto &[k, v] : h){
    s += k;
    s += " ";
    s += v;
    s += "\r\n";
  }
  s += "\r\n";
}
